///////////////////////////////////////////////////////////
// 
//  MyWindow.h
// 
//  Authors:  Jeremy Bennett
//
///////////////////////////////////////////////////////////

// Local Includes
#include "MyContext.h"
#include "MyXBoxCont.h"
#include "MySimulation.h"
#include "Marker.h"

// SDL Includes
#include <sdl.h>

// Bullet Includes
#include <BulletSoftBody/btSoftBody.h>

#include <LinearMath/btAlignedObjectArray.h>
#include <LinearMath/btVector3.h>
#include <LinearMath/btMatrix3x3.h>
#include <LinearMath/btQuickprof.h>


// System Includes

// Library Includes
#if 0
    #pragma comment(lib, "libbulletmath_d.lib")
    #pragma comment(lib, "libbulletsoftbody_d.lib")
    #pragma comment(lib, "libbulletdynamics_d.lib")
    #pragma comment(lib, "libbulletcollision_d.lib")
    #pragma comment(lib, "libbulletopenglsupport_d.lib")
#endif

//user defined
#define PI 3.141592653589793238f

// Forward Declarations
class  MyShape;
class  btRigidBody;
class  btDynamicsWorld;
class  btCollisionShape;
class  btTypedConstraint;
class  btConstraintSolver;
class  btBroadphaseInterface;
class  btCollisionDispatcher;
class  btDefaultCollisionConfiguration;
class  btSoftSoftCollisionAlgorithm;
class  btSoftRigidCollisionAlgorithm;
class  btSoftRigidDynamicsWorld;
class  GL_ShapeDrawer;
struct btCollisionAlgorithmCreateFunc;

class MyWindow
{
  public:
    // Constructor / Destructor
    MyWindow();
    ~MyWindow();
  
    // Init / Fini
    bool init();
    bool fini();

    // Execute
    bool execute( int argv, char* argc[] );

    bool setViewPort( int x, int y, int w, int h );

  protected:

    //////////////////////////////
    // Bullett
    /////

    bool _initPhysics();
    bool _finiPhysics();

    bool _resetBulletScene();

    bool _renderBulletScene();
    bool _drawLine( const btVector3& from, 
                    const btVector3& to, 
                    const btVector3& color );

    btVector3 _createPickRay( int x, int y );

    // Creation methods
    btRigidBody* _createStaticBltBox( const btVector3 &vSize, 
                                      const btVector3 &vOrigin );
	btRigidBody* _createDynamicBltBox( const btVector3 &vSize, 
                                       const btVector3 &vOrigin, 
                                       const btScalar   mass = 1.0f );
    btRigidBody* _createDynamicBltSphere( const btScalar   fRadius, 
                                          const btVector3 &vOrigin, 
                                          const btScalar   mass = 1.0f );
    btRigidBody* _createDynamicBltCylinder( const btVector3 &vSize, 
                                            const btVector3 &vOrigin, 
                                            const btScalar   mass = 1.0f );
    btRigidBody* _createDynamicBltSquare( const btVector3 &vSize, 
                                            const btVector3 &vOrigin, 
                                            const btScalar   mass = 1.0f );
    btRigidBody* _createDynamicBltRectangle( const btVector3 &vSize, 
                                            const btVector3 &vOrigin, 
                                            const btScalar   mass = 1.0f );
    btRigidBody* _createDynamicBltTriangle( const btScalar vScale, 
                                            const btScalar vThickness,
                                            const btVector3 &vOrigin, 
                                            const btScalar   mass = 1.0f );
    btRigidBody* _createDynamicBltStick( const btVector3 &vSize, 
                                         const btVector3 &vOrigin, 
                                         const btScalar   mass = 1.0f );
    btRigidBody* _createDynamicOozeBall( const btScalar   fRadius, 
                                         const btVector3 &vOrigin, 
                                         const btScalar   mass = 1.0f );
      
#if 0
    bool _findNeighbors( btRigidBody *pRigBdy );
#endif

    //////////////////////////////
    // Games
    /////
    
    bool _preFrame();
    bool _postFrame();
    bool _render();
    
    bool _handleEvents();
    bool _handleController();

    bool _handleMouseMove( int x, int y );
    bool _handleLeftMouseDown( int x, int y );
    bool _handleLeftMouseUp( int x, int y );

    //////////////////////////////
    // Common
    /////

    bool _initConfig();

    bool _initGL();
    bool _initAudio();

    bool _finiAudio();

    bool _stopAudio();

    bool _updateTime();
    bool _updateCamera();

    bool _renderPointer();

	void readFile(); //TOXIC

    //////////////////////////////
    // Common
    /////

    bool _resetShapePosition( const btVector3 &vOrgPos, float iAng );
    bool _updateStickToPosition( unsigned int iPos );
    bool _executePush( MySimPushDir eDir, unsigned int iDis );

    bool _createShape( unsigned int eShp );

	bool _setupBoard();
	void _chooseAction(int orientAngle , obj_act& oa );
	void _calculateResult(float orgAngle, float finAngle,const btVector3 &opos,const btVector3 &fpos, obj_res& or );
	void _runBabble();
    bool _invalid();
	void _runEval();
	void _setupEval();
	bool _fitsOrientation(float angDif);

    //////////////////////////////
    // Splash
    /////

    //////////////////////////////
    // Games
    /////

    int _iTotalHappiness;

    //////////////////////////////
    // Test
    /////

    // Pointers
    float _x;
    float _y;
    float _lx;
    float _ly;
    float _rx;
    float _ry;

    //////////////////////////////
    // Bullet
    //

    #define btAObjA btAlignedObjectArray

    // Environment
    btAObjA<btCollisionShape*>	             _aBltColShapes;    // Array of shapes for deletion/cleanup
    btDynamicsWorld                         *_pBltDynWorld;
	btBroadphaseInterface                   *_pBltBroadphase;   //
	btCollisionDispatcher                   *_pBltDispatcher;   //
    btConstraintSolver 	                    *_pBltConstrSolver; //
	btCollisionAlgorithmCreateFunc          *_pBBoxCrtFunc;     //
	btDefaultCollisionConfiguration         *_pDefColConf;      // Default collision configuration

	//Simulation
	btVector4                            _vCol;
	btVector3                            _rStart;
	btVector3                            _rEnd;
	btVector3                            _rCenter;
	btVector3                            _rNorm;
	btVector3                            _rHit;
	MyShape                             *_pActiveShape;      // Active shape
    MyShape                             *_pStickShape;       // Stick Shape
	MyShape								*_pTable;			 // Table
	Marker								*_pMarker;           // Marker

	//btAObjA<btSoftSoftCollisionAlgorithm*>   _aAlgSofSofCol;
	//btAObjA<btSoftRigidCollisionAlgorithm*>  _aAlgSofRigCol;

	btSoftBodyWorldInfo	                     _infoSofBdyWorld;
    
    // Picking/Manipulation
    btTypedConstraint                       *_pPickConstr;      // Picking constraint
    btRigidBody                             *_pPickRigBdy;      // Picking rigid body
    btVector3                                _vPickREnd;        //
    btVector3                                _vPickPos;         //
    float                                    _fPickDist;        // Picking distance 

    MyShape                                 *_pPickedShape;     // Picking rigid body
	btVector3                                _bMin; // vMin for Boundary
    btVector3                                _bMax; // vMax for Boundary
	// Rendering
    GL_ShapeDrawer                          *_pBltGLDrawer;     // TOXIC: Inefficient
    btClock                                  _bltClock;         // Clock
	//Eval
	btVector3								 _vShapeOrigPos;    // Position of the shape
	float                                    _fShapeOrigAng;    // orientation angle of the shape
	float						             _fMarkerOri;
	float                                    _fMarkerDis;
	float                                    _fMarkerAng;
	int										 _iConfigNum;
	int										 _iEvalPasses;       // total number of times eval is run
	int									     _dtotalMoves;        //total number of moves for the shape to reach the marker
	//Shape Marker
	btVector3								 _vMarkerPosition;  
	float									 _fMarkerAngle;


    //////////////////////////////
    // Common
    /////
	typedef enum {
        Eval_Init     = 0,
		Eval_Setup    = 1,
        Eval_Ready    = 2,
        Eval_Pushing  = 3,
        Eval_Done     = 4
    } MyEvalPhase;

    typedef enum {
        Babble_Init     = 0,
        Babble_Ready    = 1,
        Babble_Pushing  = 2,
        Babble_Done     = 3
    } MyBabblePhase;
    bool                                    _bBabble;
	bool                                    _bEval;
    float                                   _fStickDis;
    unsigned int                            _nStickMovIter; //
	btVector3                               _vStickMov;     //
    btVector3                               _vStickPos;
    btVector3                               _vDbgPos[2];
    float                                   _fDbgAng[2];
    btVector3	                            _vBabOrigPos;
    float                                   _fBabOrigAng;
    unsigned int                            _iBabSinceReset;
    unsigned int                            _iBabOrient;
    obj_act                                 _objBabAct;
    obj_res                                 _objBabRes;
    MyBabblePhase                           _eBabPhase;
	MyEvalPhase                             _eEvalPhase;
	bool									_atMaxPushes;
	int										_maxPushes;
	obj_act                                 _objEvalAct;
    obj_res                                 _objEvalRes;
	bool                                    _bShapeAtMarker;
    MySimulation                            _simulation;

    btQuaternion                            _qA;
    btQuaternion                            _qB;
    btQuaternion                            _qOrig;
    btQuaternion                            _qStart;
    btQuaternion                            _qEnd;


    struct MyPoint {
        MyPoint( float x, float y, float z ) 
          { e[0]=x; e[1]=y; e[2]=z; }
        float e[3];
    };

    std::vector<MyPoint>                    _vEvalAct;
    std::vector<MyPoint>                    _vEvalPred;

    MyContext                               _context;

    // SDL Surface
    SDL_Surface      *_pSurface;

    MyXBoxCont        _xCont;

    // Window state
    int       _w;
    int       _h;
    btVector3 _vCamPos;
    btVector3 _vCamTargPos;
    btVector3 _vCamUp;
    float     _fCamDis;
    float     _fEle;
    float     _fAzi;
    int       _iForwardAxis;

    // State Variable
    bool    _bPick;
    bool    _bSplash;
    bool    _bQuit;
};
